from fastapi import FastAPI, APIRouter, HTTPException
from fastapi.responses import JSONResponse, FileResponse
import torch
import os
import random
import numpy as np
import json
import time
import subprocess
from eyemodel.regress import EyeFeatureExtractor, BinocularSVRTracker, compute_angle_errors
from .utils.adb import ADBManager
router = APIRouter()

#需要依据你的数据位置修改
DATA_ROOT = r"files/eye/datasets"
MODEL_PATH = r"files/eye/model/nnmodel.pth"

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

feature_extractor = EyeFeatureExtractor(
    model_path=MODEL_PATH,
    device=device
)
adb_manager = ADBManager()

def load_tracker(idx):
    base_path = os.path.join(DATA_ROOT, str(idx))
    model_paths = {
        'L': os.path.join(base_path, "model/L_regressor.pkl"),
        'R': os.path.join(base_path, "model/R_regressor.pkl"),
        'two': os.path.join(base_path, "model/two_regressor.pkl"),
    }
    scaler_paths = {
        'L': os.path.join(base_path, "model/L_scaler.pkl"),
        'R': os.path.join(base_path, "model/R_scaler.pkl"),
        'two': os.path.join(base_path, "model/two_scaler.pkl"),
    }
    tracker = BinocularSVRTracker(feature_extractor, model_paths, scaler_paths)
    return tracker

@router.get("/infer/eyerandom")
def random_infer():
    try:
        all_idx = [d for d in os.listdir(DATA_ROOT) if d.isdigit()]
        if not all_idx:
            raise HTTPException(status_code=404, detail="未找到测试数据文件夹")
        idx = random.choice(all_idx)
        tracker = load_tracker(idx)
        sample_dir = os.path.join(DATA_ROOT, str(idx), "samples")

        # 加载标注文件
        label_file = os.path.join(sample_dir, "annotations.json")
        with open(label_file, 'r') as f:
            labels = json.load(f)

        item = random.choice(labels)
        img_L = os.path.join(sample_dir, item["left_img"])
        img_R = os.path.join(sample_dir, item["right_img"])
        label = np.array(item["label"])

        gaze_pred = tracker.predict_from_images(img_L_path=img_L, img_R_path=img_R)
        if gaze_pred is None:
            raise HTTPException(status_code=500, detail="推理失败，特征提取为空")

        # 计算误差角度
        error = float(compute_angle_errors([gaze_pred], [label])[0])

        return JSONResponse({
            "idx": idx,
            "left_img": img_L.replace("\\", "/"),  # 将反斜杠转换为正斜杠
            "right_img": img_R.replace("\\", "/"),  # 将反斜杠转换为正斜杠
            "pred_gaze": gaze_pred.tolist(),
            "label": label.tolist(),
            "angle_error": error
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"推理出错: {str(e)}")


@router.get("/infer/eyeall")
def infer_all():
    try:
        all_idx = sorted([d for d in os.listdir(DATA_ROOT) if d.isdigit()])
        if not all_idx:
            raise HTTPException(status_code=404, detail="未找到测试数据文件夹")

        all_results = []
        all_errors = []

        for idx in all_idx:
            tracker = load_tracker(idx)
            folder_path = os.path.join(DATA_ROOT, str(idx), "samples")
            label_file = os.path.join(folder_path, "annotations.json")
            if not os.path.exists(label_file):
                continue

            with open(label_file, 'r') as f:
                labels = json.load(f)

            error_list = []
            for item in labels:
                img_L_path = os.path.join(folder_path, item["left_img"])
                img_R_path = os.path.join(folder_path, item["right_img"])
                label = np.array(item["label"])
                gaze = tracker.predict_from_images(img_L_path=img_L_path, img_R_path=img_R_path)
                if gaze is not None:
                    error = float(compute_angle_errors([gaze], [label])[0])
                    error_list.append(error)

            if error_list:
                mean_error = float(np.mean(error_list))
                all_results.append({
                    "idx": idx,
                    "mean_error": mean_error,
                    "num_samples": len(error_list)
                })
                all_errors.extend(error_list)

        overall_mean = float(np.mean(all_errors)) if all_errors else None

        return JSONResponse({
            "results": all_results,
            "overall_mean_error": overall_mean
        })

    except Exception as e:
        raise HTTPException(status_code=500, detail=f"推理出错: {str(e)}")



@router.get("/delay")
async def test_tracking_delay(
):
    delay = adb_manager.test_delay()
    return JSONResponse(content={
        "delay": delay
    })
@router.get("/rate")
async def test_tracking_rate(
):
    total_time, total_frames,rate = adb_manager.test_rate()
    return JSONResponse(content={
        "total_time_ms": total_time,
        "total_frames": total_frames,
        "processing_rate_fps": rate
    })



@router.get("/image")
def get_eye_image(path: str):
    """
    获取眼动图像文件
    
    参数:
    - path: 图像文件路径
    """
    try:
        # 将URL中的正斜杠转换为系统路径分隔符
        normalized_path = path.replace("/", os.sep)
        
        print(f"请求的图像路径: {path}")
        print(f"标准化后的路径: {normalized_path}")
        print(f"当前工作目录: {os.getcwd()}")
        print(f"DATA_ROOT: {DATA_ROOT}")
        print(f"文件是否存在: {os.path.exists(normalized_path)}")
        
        # 检查文件是否存在
        if not os.path.exists(normalized_path):
            # 尝试相对路径
            relative_path = os.path.join(os.getcwd(), normalized_path)
            print(f"尝试相对路径: {relative_path}")
            if os.path.exists(relative_path):
                normalized_path = relative_path
            else:
                raise HTTPException(status_code=404, detail=f"图像文件不存在: {normalized_path}")
        
        # 检查文件是否在允许的目录内（安全考虑）
        # 获取绝对路径进行比较
        abs_normalized_path = os.path.abspath(normalized_path)
        abs_data_root = os.path.abspath(DATA_ROOT)
        abs_data_root_full = os.path.abspath(os.path.join(os.getcwd(), DATA_ROOT))
        
        print(f"绝对路径检查:")
        print(f"  normalized_path: {abs_normalized_path}")
        print(f"  DATA_ROOT: {abs_data_root}")
        print(f"  DATA_ROOT_FULL: {abs_data_root_full}")
        
        if not abs_normalized_path.startswith(abs_data_root) and not abs_normalized_path.startswith(abs_data_root_full):
            raise HTTPException(status_code=403, detail="访问被拒绝：文件路径不在允许的目录内")
        
        print(f"最终返回路径: {normalized_path}")
        # 返回文件
        return FileResponse(normalized_path)
        
    except HTTPException:
        raise
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"获取图像失败: {str(e)}")
if __name__ == "__main__":
    adb = ADBManager()
    adb.test_delay()

# @router.get("/delay")
# def test_eye_delay():
#     """
#     测试眼动追踪延迟
#     返回单次追踪任务的执行时间（微秒）
#     """
#     try:
#         # 使用二进制文件测试延迟
#         delay_binary = os.path.join("files", "eye", "libs", "delay")
#         if not os.path.exists(delay_binary):
#             raise HTTPException(status_code=404, detail="延迟测试工具不存在")
        
#         # 执行延迟测试
#         result = subprocess.run([delay_binary], capture_output=True, text=True, timeout=30)
        
#         if result.returncode != 0:
#             raise HTTPException(status_code=500, detail=f"延迟测试失败: {result.stderr}")
        
#         # 解析结果
#         try:
#             delay_us = int(result.stdout.strip())
#         except ValueError:
#             raise HTTPException(status_code=500, detail="延迟测试结果格式错误")
        
#         return JSONResponse({"delay": delay_us})
        
#     except subprocess.TimeoutExpired:
#         raise HTTPException(status_code=500, detail="延迟测试超时")
#     except Exception as e:
#         raise HTTPException(status_code=500, detail=f"延迟测试失败: {str(e)}")


# @router.get("/rate")
# def test_eye_rate():
#     """
#     测试眼动追踪帧率
#     返回处理帧率和性能统计
#     """
#     try:
#         # 使用二进制文件测试帧率
#         rate_binary = os.path.join("files", "eye", "libs", "rate")
#         if not os.path.exists(rate_binary):
#             raise HTTPException(status_code=404, detail="帧率测试工具不存在")
        
#         # 执行帧率测试
#         result = subprocess.run([rate_binary], capture_output=True, text=True, timeout=60)
        
#         if result.returncode != 0:
#             raise HTTPException(status_code=500, detail=f"帧率测试失败: {result.stderr}")
        
#         # 解析结果
#         try:
#             lines = result.stdout.strip().split('\n')
#             if len(lines) < 3:
#                 raise ValueError("帧率测试结果格式错误")
            
#             total_time_ms = float(lines[0])
#             total_frames = int(lines[1])
#             processing_rate_fps = float(lines[2])
            
#         except (ValueError, IndexError) as e:
#             raise HTTPException(status_code=500, detail=f"帧率测试结果解析失败: {str(e)}")
        
#         return JSONResponse({
#             "total_time_ms": total_time_ms,
#             "total_frames": total_frames,
#             "processing_rate_fps": processing_rate_fps
#         })
        
#     except subprocess.TimeoutExpired:
#         raise HTTPException(status_code=500, detail="帧率测试超时")
#     except Exception as e:
#         raise HTTPException(status_code=500, detail=f"帧率测试失败: {str(e)}")


# app.include_router(router, prefix="/api")

# 启动方式: uvicorn filename:app --reload
